
#pragma once

namespace atr {

/**
 * @brief Namespace only for internal use of atr library
 * @details Please don't use this namespace outside the atr library. IF you REALLY need to - do it with special care.
 */
namespace __ {

template <template <class> class Predicate, class Prevs, class Nexts, bool isGood>
    struct __remove_if;

template <template <class> class Predicate,
          template <class ...> class Base, class ... Prevs, class Next>
struct __remove_if<Predicate, Base<Prevs...>, Base<Next>, true>
{
    using type = Base<Prevs..., Next>;
};

template <template <class> class Predicate,
          template <class ...> class Base, class ... Prevs, class Next>
struct __remove_if<Predicate, Base<Prevs...>, Base<Next>, false>
{
    using type = Base<Prevs...>;
};

template <template <class> class Predicate,
          template <class ...> class Base, class ... Prevs,
          class First, class Second, class ... Nexts>
struct __remove_if<Predicate,
                   Base<Prevs...>,
                   Base<First, Second, Nexts...>,
                   true>
    : public __remove_if<Predicate,
                         Base<Prevs..., First>,
                         Base<Second, Nexts...>,
                         !Predicate<Second>::value> {};

template <template <class> class Predicate,
          template <class ...> class Base, class ... Prevs,
          class First, class Second, class ... Nexts>
struct __remove_if<Predicate,
                   Base<Prevs...>,
                   Base<First, Second, Nexts...>,
                   false>
    : public __remove_if<Predicate,
                         Base<Prevs...>,
                         Base<Second, Nexts...>,
                         !Predicate<Second>::value> {};

} // namespace __
} // namespace atr
